/**
 * @class   wosh::gui::WidgetProperties
 * @brief   Shows Properties (PropertiesProvider) and allow user
 *          to edit then (asynch, remote through bus messages).
 *
 ****************************************************************************
 * @version $Id: WidgetProperties.h 2184 2010-03-20 13:19:23Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Gui_WidgetProperties_H__
 #define __WOSH_Gui_WidgetProperties_H__

#include <core/PropertiesProvider.h>
#include <core/NEW_List.h>
#include <core/Message.h>

#include <framework/gui/IWidget.h>
#include <framework/gui/WoshTableModel.h>

 #include <core/Property.h>
 #include <core/Table.h>
 #include <core/MethodsDef.h>
 #include <QMap>
 #include <QSignalMapper>


using namespace wosh;

namespace Ui {
    class WidgetProperties;
}
namespace wosh {
 namespace gui {



class WidgetProperties :  public QWidget, public IWidget  {

	Q_OBJECT

	public:

		WidgetProperties(QWidget *parent = 0);
		virtual ~WidgetProperties();

	public:
		
		virtual WRESULT updateTable( const Table* table );
		virtual WRESULT loadTable( const Table* table );


	public:

		virtual QWidget* asQWidget()		{ return this; }

		virtual void busMessage( const Message& message, const Bus* source );

		virtual void setTargetURI( const URI& uri );
 
	protected:
		void changeEvent(QEvent *e);

	protected:
		virtual void contextMenuEvent( QContextMenuEvent* menu_event );

		void refreshData( bool force_all );

	public slots:

		virtual void refreshAll()			{ refreshData(true); }
		virtual WRESULT refreshSmart()		{ refreshData(false); return WRET_OK; }

		virtual WRESULT reset();

	protected slots:
		void cell_valueChanged( unsigned int row, unsigned int col, ISerializable* newValue );

	signals:
		void updateClicked();


	protected:
		void buildMenus();

		QMenu* menuKey;
		QAction* actionKeyUpdate;
		QAction* actionKeyCopyTo;
		QAction* actionKeyNew;
		QAction* actionKeyMan;

		QMenu* menuValue;
		QAction* actionValueUpdate;

		QMenu* menuPerm;
		QAction* actionPermChange;


	private:
		Ui::WidgetProperties *m_ui;

}; // class def


class PropertiesMapper : public QObject {

	Q_OBJECT

	public:
		PropertiesMapper( QObject* parent = NULL, bool allow_editing = false ) : QObject(parent) {
			this->signalMapper = NULL;
			if ( allow_editing ) {
				this->signalMapper = new QSignalMapper(this);
				connect(this->signalMapper, SIGNAL(mapped(const QString &)), this, SLOT(apply_property(const QString &)));
			}
		 }
		virtual ~PropertiesMapper() { }



	public slots:
		bool evalResponse( const Response* response ) {
			if ( response == NULL ) return false;
			if ( !response->hasData() ) return false;
			if ( response->getMethod() == _METHOD_SetProperty
				 || response->getMethod() == _METHOD_GetProperty
				 || response->getMethod() == _METHOD_GetProperties 
				 || response->getMethod() == _METHOD_ListProperties )
				{
				if ( response->getData()->isClass(_Property_TYPE) ) {
					return evalProperty( response->getData()->as<Property>() );
				 }
				if ( response->getData()->isClass(_Table_TYPE) ) {
					return evalProperties( response->getData()->as<Table>() );
				 }
				if ( response->getData()->isClass(_NEW_List_TYPE) ) {
					return evalProperties( response->getData()->as<NEW_List>() );
				 }
			 }
			return false;
		 }


		bool evalProperties( const Table* propTable ) {
			if ( propTable == NULL ) return false;
			bool updated = false;
			unsigned int rows = propTable->getRows();
			for (unsigned int row=0; row<rows; row++) {
				const ISerializable* objName = propTable->get(row,0);
				if ( objName == NULL ) continue;
				if ( objName->isClass(_Property_TYPE) ) {
					updated |= evalProperty( objName->as<Property>() );
				 }
				else if ( !objName->isClass(_Variant_TYPE) )
					continue;

				const wosh::Variant* dataName = dynamic_cast<const wosh::Variant*>(objName);
				const ISerializable* objValue = propTable->get(row,1);
				if ( dataName == NULL || objValue == NULL || !objValue->isClass(_Variant_TYPE) )
					continue;
				const wosh::Variant* dataValue = dynamic_cast<const wosh::Variant*>(objValue);
				if ( dataName == NULL )
					continue;

				updated |= evalProperty( dataName->toString(), *dataValue );
			 }
			return updated;
		 }
		bool evalProperties( const NEW_List* propList ) {
			if ( propList == NULL ) return false;
			bool updated = false;
			NEW_List::ConstIterator it;
			NEW_List::ConstIterator it_end = propList->end();
			for( it=propList->begin(); it!=it_end; ++it ) {
				if ( *it == NULL || !(*it)->isClass(_Property_TYPE) ) continue;
				updated |= evalProperty( (*it)->as<Property>() );
			 }
			return updated;
		 }

		ISerializable* getObject( const QString& key ) {
			if ( !map.contains( key ) )
				return NULL;
			IWidgetSerializable* editor = map.value( key );
			if ( editor == NULL )
				return NULL;
			return editor->saveObject();
		 }

		NEW_List* createKeysNEW_List() {
			NEW_List* dl = new NEW_List();
			QMap<QString, IWidgetSerializable*>::const_iterator i = map.constBegin();
			while (i != map.constEnd()) {
				dl->push_back<Variant>( i.key().toLatin1().data() );
				++i;
			}
			return dl;
		 }

	public:
		bool evalProperty( const wosh::Property* propObj ) {
			if ( propObj == NULL ) return false;
			return evalProperty( propObj->getKey(), propObj->getValue(), &propObj->getPermission() );
		 }

		bool evalProperty( const std::string& key, const Variant& value, const Permission* permission = NULL ) {
			if ( !map.contains( key.c_str() ) )
				return false;
			IWidgetSerializable* iWidgetSer = map.value( key.c_str() );
			if ( iWidgetSer == NULL )
				return false;
			iWidgetSer->loadObject(&value);
			emit parsedProperty( key, &value, permission, iWidgetSer );
			return true;
		 }

	protected slots:
		void apply_property( const QString& prop_key ) {
			IWidgetSerializable* label = map.value( prop_key );
			if ( label == NULL )
				return;
			Variant value;
			label->saveObject(&value);
			NEW_List* dl = new NEW_List();
			dl->push_back<Variant>( prop_key.toLatin1().data() );
			dl->push_back( value.clone() );
			emit send_request(_METHOD_SetProperty, dl);
		 }

	signals:
		void parsedProperty( const std::string& key, const Variant* value, const Permission* permission, IWidgetSerializable* widget );
		void send_request( const QString& method, ISerializable* argument );

	public:
		void set( const std::string& key, IWidgetSerializable* widget, bool disable_update = false ) {
			if ( key.empty() || widget == NULL )
				return;
			this->map.insert(key.c_str(), widget);
			if ( this->signalMapper == NULL || disable_update )
				return;
			connect(widget->asQWidget(), SIGNAL(updatedObject()), this->signalMapper, SLOT(map()));
			this->signalMapper->setMapping(widget->asQWidget(), key.c_str() );
		 }

		QMap<QString, IWidgetSerializable*>& getMap()	{ return this->map; }

	protected:
		QMap<QString, IWidgetSerializable*> map;
		QSignalMapper* signalMapper;

};












 }; // namespace gui
}; // namespace wosh


#endif //__WOSH_Gui_WidgetProperties_H__
